home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / pcb-1.000 / pcb-1 / pcb-1.3 / undo.c < prev    next >
C/C++ Source or Header  |  1995-02-27  |  14KB  |  553 lines

  1. /*
  2.  *                            COPYRIGHT
  3.  *
  4.  *  PCB, interactive printed circuit board design
  5.  *  Copyright (C) 1994,1995 Thomas Nau
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  *  Contact addresses for paper mail and Email:
  22.  *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
  23.  *  Thomas.Nau@rz.uni-ulm.de
  24.  *
  25.  */
  26.  
  27. static    char    *rcsid = "$Header: /sda4/users/nau/src/pcb/RCS/undo.c,v 1.1 1995/01/14 18:29:08 nau Exp nau $";
  28.  
  29. /* functions used to undo operations
  30.  *
  31.  * Description:
  32.  * There are two lists which hold
  33.  *   - information about a command
  34.  *   - data of removed objects
  35.  * Both lists are organized as first-in-last-out which means that the undo
  36.  * list can always use the last entry of the remove list.
  37.  * A serial number is incremented whenever an operation is completed.
  38.  * An operation itself may consist of several basic instructions.
  39.  * E.g.: removing all selected objects is one operation with exactly one
  40.  * serial number even if the remove function is called several times.
  41.  *
  42.  * a lock flag ensures that no infinite loops occure
  43.  */
  44.  
  45. #include <memory.h>
  46.  
  47. #include "global.h"
  48.  
  49. #include "buffer.h"
  50. #include "change.h"
  51. #include "create.h"
  52. #include "data.h"
  53. #include "draw.h"
  54. #include "error.h"
  55. #include "mymem.h"
  56. #include "misc.h"
  57. #include "move.h"
  58. #include "polygon.h"
  59. #include "remove.h"
  60. #include "search.h"
  61. #include "set.h"
  62. #include "undo.h"
  63.  
  64. /* ---------------------------------------------------------------------------
  65.  * some local defines
  66.  */
  67. #define    SIZE_LIMIT        (100*1024)        /* warning limit 100k */
  68.  
  69. /* ---------------------------------------------------------------------------
  70.  * some local data types
  71.  */
  72. typedef struct                    /* information about a change command */
  73. {
  74.     char            *Name;
  75. } ChangeNameType, *ChangeNameTypePtr;
  76.  
  77. typedef struct                    /* information about a move command */
  78. {
  79.     Position        DX,            /* movement vector */
  80.                     DY;
  81. } MoveType, *MoveTypePtr;
  82.  
  83. typedef struct                    /* information about removed polygon points */
  84. {
  85.     PolygonPointType    Point;    /* data */
  86.     Cardinal            Index;    /* index in polygons array of points */
  87. } RemovedPointType, *RemovedPointTypePtr;
  88.  
  89. typedef struct                    /* information about inserted polygon points */
  90. {
  91.     int                ID;            /* ID of inserted point */
  92. } InsertedPointType, *InsertedPointTypePtr;
  93.  
  94. typedef    struct                    /* holds information about an operation */
  95. {
  96.     int                Serial,        /* serial number of operation */
  97.                     Type,        /* type of operation */
  98.                     ID;            /* object ID */
  99.     union                        /* some additional information */
  100.     {
  101.         ChangeNameType        ChangeName;
  102.         MoveType            Move;
  103.         RemovedPointType    RemovedPoint;
  104.         InsertedPointType    InsertedPoint;
  105.     } Data;
  106. } UndoListType, *UndoListTypePtr;
  107.  
  108. /* ---------------------------------------------------------------------------
  109.  * some local identifiers
  110.  */
  111. static    DataTypePtr        RemoveList;        /* list of removed objects */
  112. static    UndoListTypePtr    UndoList;        /* list of operations */
  113. static    int                Serial;            /* serial number */
  114. static    size_t            UndoN,            /* number of entries */
  115.                         UndoMax;
  116. static    Boolean            Locked = False;    /* do not add entries if */
  117.                                         /* flag is set; prevents from */
  118.                                         /* infinite loops */
  119.  
  120. /* ---------------------------------------------------------------------------
  121.  * some local prototypes
  122.  */
  123. static    UndoListTypePtr    GetUndoSlot(int, int);
  124. static    void            DrawRecoveredObject(int, void *, void *);
  125. static    Boolean            UndoChangeName(UndoListTypePtr);
  126. static    Boolean            UndoCopy(UndoListTypePtr);
  127. static    Boolean            UndoMove(UndoListTypePtr);
  128. static    Boolean            UndoRemove(UndoListTypePtr);
  129. static    Boolean            UndoRemovePolygonPoint(UndoListTypePtr);
  130. static    Boolean            UndoInsertPolygonPoint(UndoListTypePtr);
  131.  
  132. /* ---------------------------------------------------------------------------
  133.  * adds a command plus some data to the undo list
  134.  */
  135. static UndoListTypePtr GetUndoSlot(int CommandType, int ID)
  136. {
  137.             UndoListTypePtr    ptr;
  138.     static    size_t            limit = SIZE_LIMIT;
  139.  
  140.         /* allocate memory */
  141.     if (UndoN >= UndoMax)
  142.     {
  143.         size_t    size;
  144.  
  145.         UndoMax += STEP_UNDOLIST;
  146.         size = UndoMax *sizeof(UndoListType);
  147.         UndoList = (UndoListTypePtr) MyRealloc(UndoList, size,
  148.             "AddCommandToUndoList()");
  149.         memset(&UndoList[UndoN], 0, STEP_REMOVELIST *sizeof(UndoListType));
  150.  
  151.             /* ask user to flush the table because of it's size */
  152.         if (size > limit)
  153.         {
  154.             limit = (size /SIZE_LIMIT +1) *SIZE_LIMIT;
  155.             Message(False, "size of 'undo-list' exceeds %li kb\n",
  156.                 (long) (size >> 10));
  157.         }
  158.     }
  159.  
  160.         /* copy typefield and serial number to the list */
  161.     ptr = &UndoList[UndoN++]; 
  162.     ptr->Type = CommandType;
  163.     ptr->ID = ID;
  164.     ptr->Serial = Serial;
  165.     return(ptr);
  166. }
  167.  
  168. /* ---------------------------------------------------------------------------
  169.  * redraws the recovered object
  170.  */
  171. static void DrawRecoveredObject(int Type, void *Ptr1, void *Ptr2)
  172. {
  173.     if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE))
  174.     {
  175.         LayerTypePtr    layer;
  176.  
  177.         layer= &PCB->Data->Layer[GetLayerNumber(RemoveList,(LayerTypePtr)Ptr1)];
  178.         if (layer->On)
  179.             switch(Type)
  180.             {
  181.                 case LINE_TYPE:
  182.                     DrawLine(layer, (LineTypePtr) Ptr2);
  183.                     break;
  184.  
  185.                 case TEXT_TYPE:
  186.                     DrawText(layer, (TextTypePtr) Ptr2);
  187.                     break;
  188.  
  189.                 case POLYGON_TYPE:
  190.                     DrawPolygon(layer, (PolygonTypePtr) Ptr2);
  191.                     break;
  192.             }
  193.     }
  194.     else
  195.         switch(Type)
  196.         {
  197.             case ELEMENT_TYPE:
  198.                 if (PCB->ElementOn)
  199.                     DrawElement((ElementTypePtr) Ptr2);
  200.                 break;
  201.  
  202.             case ELEMENTNAME_TYPE:
  203.                 if (PCB->ElementOn)
  204.                     DrawElementName((ElementTypePtr) Ptr1);
  205.                 break;
  206.  
  207.             case PIN_TYPE:
  208.                 if (PCB->PinOn)
  209.                     DrawPin((PinTypePtr) Ptr2);
  210.                 break;
  211.  
  212.             case VIA_TYPE:
  213.                 if (PCB->ViaOn)
  214.                     DrawVia((PinTypePtr) Ptr2);
  215.                 break;
  216.         }
  217. }
  218.  
  219. /* ---------------------------------------------------------------------------
  220.  * recovers an object from a 'change name' operation
  221.  * returns True if anything has been recovered
  222.  */
  223. static Boolean UndoChangeName(UndoListTypePtr Entry)
  224. {
  225.     void    *ptr1, *ptr2;
  226.     int        type;
  227.  
  228.         /* lookup entry by it's ID */
  229.     type = SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID);
  230.     if (type != NO_TYPE)
  231.     {
  232.         SaveFree(ChangeObjectName(type, ptr1, ptr2,
  233.             Entry->Data.ChangeName.Name));
  234.         return(True);
  235.     }
  236.     return(False);
  237. }
  238.  
  239. /* ---------------------------------------------------------------------------
  240.  * recovers an object from a 'copy' operation
  241.  * returns True if anything has been recovered
  242.  */
  243. static Boolean UndoCopy(UndoListTypePtr Entry)
  244. {
  245.     void    *ptr1, *ptr2;
  246.     int        type;
  247.  
  248.         /* lookup entry by it's ID */
  249.     type = SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID);
  250.     if (type != NO_TYPE)
  251.     {
  252.         DestroyObject(type, ptr1, ptr2);
  253.         return(True);
  254.     }
  255.     return(False);
  256. }
  257.  
  258. /* ---------------------------------------------------------------------------
  259.  * recovers an object from a 'move' operation
  260.  * returns True if anything has been recovered
  261.  */
  262. static Boolean UndoMove(UndoListTypePtr Entry)
  263. {
  264.     void    *ptr1, *ptr2;
  265.     int        type;
  266.  
  267.         /* lookup entry by it's ID */
  268.     type = SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID);
  269.     if (type != NO_TYPE)
  270.     {
  271.         MoveObject(type,ptr1,ptr2, -Entry->Data.Move.DX, -Entry->Data.Move.DY);
  272.         return(True);
  273.     }
  274.     return(False);
  275. }
  276.  
  277. /* ----------------------------------------------------------------------
  278.  * recovers an object from a 'remove' operation
  279.  * returns True if anything has been recovered
  280.  */
  281. static Boolean UndoRemove(UndoListTypePtr Entry)
  282. {
  283.     void    *ptr1, *ptr2;
  284.     int        type;
  285.  
  286.         /* lookup entry by it's ID */
  287.     type = SearchObjectByID(RemoveList, &ptr1, &ptr2, Entry->ID);
  288.     if (type != NO_TYPE)
  289.     {
  290.         DrawRecoveredObject(type, ptr1, ptr2);
  291.         MoveObjectToBuffer(PCB->Data, RemoveList, type, ptr1, ptr2);
  292.         return(True);
  293.     }
  294.     return(False);
  295. }
  296.  
  297. /* ---------------------------------------------------------------------------
  298.  * recovers a removed polygon point
  299.  * returns true on success
  300.  */
  301. static Boolean UndoRemovePolygonPoint(UndoListTypePtr Entry)
  302. {
  303.     void    *ptr1, *ptr2;
  304.  
  305.         /* lookup entry (polygon not point was saved) by it's ID */
  306.     if (SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID) == POLYGON_TYPE)
  307.     {
  308.         LayerTypePtr    layer = (LayerTypePtr) ptr1;
  309.         PolygonTypePtr    polygon = (PolygonTypePtr) ptr2;
  310.  
  311.             /* recover the point */
  312.         if (layer->On)
  313.         {
  314.             ErasePolygon(polygon);
  315.             InsertPointIntoPolygon(polygon, Entry->Data.RemovedPoint.Index,
  316.                 Entry->Data.RemovedPoint.Point.X,
  317.                 Entry->Data.RemovedPoint.Point.Y);
  318.             DrawPolygon(layer, polygon);
  319.         }
  320.         else
  321.             InsertPointIntoPolygon(polygon, Entry->Data.RemovedPoint.Index,
  322.                 Entry->Data.RemovedPoint.Point.X,
  323.                 Entry->Data.RemovedPoint.Point.Y);
  324.         return(True);
  325.     }
  326.     return(False);
  327. }
  328.  
  329. /* ---------------------------------------------------------------------------
  330.  * recovers an inserted polygon point
  331.  * returns true on success
  332.  */
  333. static Boolean UndoInsertPolygonPoint(UndoListTypePtr Entry)
  334. {
  335.     void    *ptr1, *ptr2;
  336.  
  337.         /* lookup entry (polygon not point was saved) by it's ID */
  338.     if (SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID) == POLYGON_TYPE)
  339.     {
  340.         PolygonTypePtr        polygon = (PolygonTypePtr) ptr2;
  341.  
  342.             /* lookup point by it's ID */
  343.         POLYGONPOINT_LOOP(polygon,
  344.             if (point->ID == Entry->Data.InsertedPoint.ID)
  345.             {
  346.                 RemovePolygonPoint(polygon, point);
  347.                 return(True);
  348.             }
  349.         );
  350.     }
  351.     return(False);
  352. }
  353.  
  354. /* ---------------------------------------------------------------------------
  355.  * undo of any 'hard to recover' operation
  356.  * supported are MOVE, CREATE, REMOVE and CHANGENAME
  357.  *
  358.  * returns True if anything is has been done
  359.  */
  360. Boolean Undo(void)
  361. {
  362.     UndoListTypePtr    ptr;
  363.     Boolean            changed = False;
  364.  
  365.     if (!UndoN)
  366.         return(False);
  367.  
  368.         /* lock undo module to prevent from loops
  369.          * and loop over all entries with the same serial number
  370.          */
  371.     LockUndo();
  372.     ptr = &UndoList[UndoN -1];
  373.     Serial = ptr->Serial;
  374.     for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--)
  375.         switch(ptr->Type)
  376.         {
  377.             case UNDO_CHANGENAME:
  378.                 changed |= UndoChangeName(ptr);
  379.                 break;
  380.  
  381.             case UNDO_COPY:
  382.                 changed |= UndoCopy(ptr);
  383.                 break;
  384.  
  385.             case UNDO_MOVE:
  386.                 changed |= UndoMove(ptr);
  387.                 break;
  388.  
  389.             case UNDO_REMOVE:
  390.                 changed |= UndoRemove(ptr);
  391.                 break;
  392.  
  393.             case UNDO_REMOVE_POLYGON_POINT:
  394.                 changed |= UndoRemovePolygonPoint(ptr);
  395.                 break;
  396.  
  397.             case UNDO_INSERT_POLYGON_POINT:
  398.                 changed |= UndoInsertPolygonPoint(ptr);
  399.                 break;
  400.         }
  401.  
  402.         /* release lock */
  403.     UnlockUndo();
  404.     return(changed);
  405. }
  406.  
  407. /* ---------------------------------------------------------------------------
  408.  * increments the serial number of the undo list
  409.  * it's not done automatically because some operations perform more
  410.  * than one request with the same serial #
  411.  */
  412. void IncrementUndoSerialNumber(void)
  413. {
  414.     if (!Locked)
  415.         Serial++;
  416. }
  417.  
  418. /* ---------------------------------------------------------------------------
  419.  * releases memory of the undo- and remove list
  420.  */
  421. void ClearUndoList(void)
  422. {
  423.     UndoListTypePtr        undo;
  424.  
  425.         /* release memory allocated by objects in undo list */
  426.     for (undo = UndoList; UndoN; undo++, UndoN--)
  427.         if (undo->Type == UNDO_CHANGENAME)
  428.             SaveFree(undo->Data.ChangeName.Name);
  429.     MyFree((char **) &UndoList);
  430.     FreeDataMemory(RemoveList);
  431.  
  432.         /* reset some counters */
  433.     UndoN = UndoMax = 0;
  434.     Serial = 0;
  435. }
  436.  
  437. /* ---------------------------------------------------------------------------
  438.  * adds an object to the list of removed objects and removes it from
  439.  * the current PCB
  440.  */
  441. void MoveObjectToRemoveUndoList(int Type, void *Ptr1, void *Ptr2)
  442. {
  443.     UndoListTypePtr    undo;
  444.  
  445.     if (!Locked)
  446.     {
  447.         if (!RemoveList)
  448.             RemoveList = CreateNewBuffer();
  449.  
  450.         undo = GetUndoSlot(UNDO_REMOVE, OBJECT_ID(Ptr2));
  451.         MoveObjectToBuffer(RemoveList, PCB->Data, Type, Ptr1, Ptr2);
  452.     }
  453. }
  454.  
  455. /* ---------------------------------------------------------------------------
  456.  * adds an object to the list of removed polygon points
  457.  */
  458. void AddObjectToRemovePolygonPointUndoList(PolygonTypePtr Polygon,
  459.     PolygonPointTypePtr Point)
  460. {
  461.     UndoListTypePtr    undo;
  462.  
  463.     if (!Locked)
  464.     {
  465.             /* the ID of the polygon is used instead */
  466.         undo = GetUndoSlot(UNDO_REMOVE_POLYGON_POINT, Polygon->ID);
  467.         undo->Data.RemovedPoint.Point = *Point;
  468.  
  469.             /* get index in array of points */
  470.         POLYGONPOINT_LOOP(Polygon,
  471.             if (point == Point)
  472.             {
  473.                 undo->Data.RemovedPoint.Index = n;
  474.                 break;
  475.             }
  476.         );
  477.     }
  478. }
  479.  
  480. /* ---------------------------------------------------------------------------
  481.  * adds an object to the list of inserted polygon points
  482.  */
  483. void AddObjectToInsertPolygonPointUndoList(PolygonTypePtr Polygon,
  484.     PolygonPointTypePtr Point)
  485. {
  486.     UndoListTypePtr    undo;
  487.  
  488.     if (!Locked)
  489.     {
  490.             /* the ID of the polygon is used instead */
  491.         undo = GetUndoSlot(UNDO_INSERT_POLYGON_POINT, Polygon->ID);
  492.         undo->Data.InsertedPoint.ID = Point->ID;
  493.     }
  494. }
  495.  
  496. /* ---------------------------------------------------------------------------
  497.  * adds an object to the list of copied objects
  498.  */
  499. void AddObjectToCopyUndoList(int Type, void *Ptr1, void *Ptr2)
  500. {
  501.     UndoListTypePtr    undo;
  502.  
  503.     if (!Locked)
  504.         undo = GetUndoSlot(UNDO_COPY, OBJECT_ID(Ptr2));
  505. }
  506.  
  507. /* ---------------------------------------------------------------------------
  508.  * adds an object to the list of moved objects
  509.  */
  510. void AddObjectToMoveUndoList(int Type, void *Ptr1, void *Ptr2,
  511.     Position DX, Position DY)
  512. {
  513.     UndoListTypePtr    undo;
  514.  
  515.     if (!Locked)
  516.     {
  517.         undo = GetUndoSlot(UNDO_MOVE, OBJECT_ID(Ptr2));
  518.         undo->Data.Move.DX = DX;
  519.         undo->Data.Move.DY = DY;
  520.     }
  521. }
  522.  
  523. /* ---------------------------------------------------------------------------
  524.  * adds an object to the list of objects with changed names
  525.  */
  526. void AddObjectToChangeNameUndoList(int Type, void *Ptr1, void *Ptr2,
  527.     char *OldName)
  528. {
  529.     UndoListTypePtr    undo;
  530.  
  531.     if (!Locked)
  532.     {
  533.         undo = GetUndoSlot(UNDO_CHANGENAME, OBJECT_ID(Ptr2));
  534.         undo->Data.ChangeName.Name = OldName;
  535.     }
  536. }
  537.  
  538. /* ---------------------------------------------------------------------------
  539.  * set lock flag
  540.  */
  541. void LockUndo(void)
  542. {
  543.     Locked = True;
  544. }
  545.  
  546. /* ---------------------------------------------------------------------------
  547.  * reset lock flag
  548.  */
  549. void UnlockUndo(void)
  550. {
  551.     Locked = False;
  552. }
  553.